CENM (Corda Enterprise Network Manager) を動かす
https://docs.cenm.r3.com/_images/enm-high-level.png
CENMクイックスタートを参考に動かしていく
目標
ひとまず localで構築してみる
サーバー上で動かすのは別記事
環境
Corda Enterprise Network Manager を ココ からDownload 1.1を使う
Requirements
Java 8
Downloadしたzipに入っている以下の3つ
Identity Manager distribution zip
Network Map distribution zip
PKI Tool distribution zip
Cordapp
PKIで鍵等を生成する(Trust Root)
code:pki-generation.conf
certificates = {
"::CORDA_TLS_CRL_SIGNER" = {
crl = {
indirectIssuer = true
file = "./crl-files/tls.crl"
issuer = "CN=Test TLS Signer Certificate, OU=Corda, O=R3 HoldCo LLC, L=New York, C=US"
}
},
"::CORDA_ROOT" = {
crl = {
file = "./crl-files/root.crl"
}
}
"::CORDA_SUBORDINATE" = {
crl = {
file = "./crl-files/subordinate.crl"
}
},
"::CORDA_IDENTITY_MANAGER",
"::CORDA_NETWORK_MAP"
}
java -jar pkitool.jar --config-file pki-generation.conf で鍵生成
--ignore-missing-crl はテスト用なので本番では使わない。
生成されるfileは以下の通り
crl-files
root.crl
subordinate.crl
tls.crl
key-stores
corda-network-map-keys.jks : network map service nodeが使用するkey pairと証明書
corda-identity-manager-keys.jks : identity managerが使用するkey pairと証明書
corda-root-keys.jks : Trust Rootのkey pairと証明書。この鍵でsubordinate-keysを生成する
corda-subordinate-keys.jks : Root keys から生成されるkey pairと証明書。この鍵でnetwork map の鍵とidentity managerの鍵を生成する
corda-tls-crl-signer-keys.jks : CRLに署名するkey pairと証明書。CRLの変更権限(他のNodeの鍵を無効にできるのは誰か)によって取り扱いを決める
trust-stores
network-root-truststore.jks : Root CAの公開鍵とオレオレ証明書。他のkeyの証明書を検証していく際に最後に必要となる。Notaryを含め、全Nodeが持っている必要があり、他のnodeからのresponseが正当なnetwork 参加者からのものかどうかを検証するのに使用する。
TODO
パスワード変更
PKIパラメータ設定例
Identity Managerを動かす
PKI で作成した Identity Manager用の鍵 corda-identity-manager-keys.jks をidentity-manager.jarと同じdirに配置
documentにあるconf 通りにidentity-manager.confを作成後、java -jar identitymanager.jar --config-file identity-manager.conf 実行で起動 identity-manager.confに書いてある設定でssh接続できる
例 ) ssh testuser@localhost -p 10002
TODO
データベース変更
SSH閉じる
Identity Managerパラメータ設定例
NotaryをIdentity Managerに登録する
corda.jarを用意
PKIで作成した network-root-truststore.jks を corda.jarと同じdirに配置
documentにあるconf 通り に node.confを作成後、(Identity Managerを起動している状態で) java -jar corda.jar --initial-registration --network-root-truststore-password trustpass --network-root-truststore network-root-truststore.jks実行 この時、既存のadditional-node-infos、certificates、network-parametersディレクトリ内にファイルがある場合は削除する必要がある
polling startしてから少し時間がかかるが落ち着いて待つべし
shuntak.icon > 体感で20分ほどかかったので、諦めない心が大切
Etaro.icon > 僕は3分くらい 笑
shuntak.icon > identity-manager.conf のsignIntervalとupdateIntervalを1000に減らしたら速くなった(たぶん負荷上がるので本番では注意)
code:log
Start polling server for certificate signing approval.
Certificate signing request approved, storing private key with the certificate chain.
Private key 'cordaclientca' and its certificate-chain stored successfully.
Generating SSL certificate for node messaging service.
SSL private key and certificate chain stored in ....
Generating trust store for corda node.
Node trust store stored in ....
Successfully registered Corda node with compatibility zone, node identity keys and certificates are stored in '...', it is advised to backup the private keys and certificates.
Corda node will now terminate.
すると、IdentityManagerにNotaryがregisterされる
certificates directoryに ( corda-identity-manager-keys.jksで) nodekeystore.jks sslkeystore.jks truststore.jks が生成され、Notaryに付与される
ちなみにこの時点で NotaryをIdentity Managerに登録する必要があるのは、Network Mapがnetwork parametersの初期設定をする際に、networkで使用するnotaryのリストを含めなければならないため。
Network Map Serviceの設定
PKIで生成した corda-network-map-keys.jksと network-root-truststore.jks を networkmap.jarと同じdirに配置
初期Network Parametersを設定する
Network Map Serviceを動かす前に、network parametersを設定しておかなくてはならない
networkmap.jarを “set network parameters” modeで動作させることで設定できる
document に従って、network-map.confとnetwork-parameters.confを作成
network-parameters.conf内の NODE INFO FILEは、Notary dir内のnodeInfo-EA502E2B986C26F9A584B17C020FA06E3C985977F4CF34FCC9879D26BED4932Aファイルへのpathを指定する
java -jar networkmap.jar --config-file network-map.conf --set-network-parameters network-parameters.conf --network-truststore network-root-truststore.jks --truststore-password trustpass --root-alias cordarootcaを実行して初期network parametersを設定する
以下のような結果が返ってくる
code:result
NetworkParameters {
minimumPlatformVersion=3
maxMessageSize=10485760
maxTransactionSize=10485760
whitelistedContractImplementations {
}
eventHorizon=PT720H
packageOwnership {
}
modifiedTime=2019-12-10T02:07:55.898Z
epoch=1
}
TODO
Network Map Serviceと異なるサーバーで動くNotaryからnodeInfoを共有する方法
scpで送るとか?
複数のNetwork Map Serviceを起動し、ALB経由でサービス提供し、正常にNotaryやNodeから利用できるか確認
Network Map Service 設定例
Network Map Serviceを動かす
java -jar networkmap.jar --config-file network-map.conf で起動
network-map.confに記述した設定でssh接続できる
例 ) ssh testuser@localhost -p 20002
Etaro.icon > view publicNetworkParticipantsでNetwork Mapに登録されているNode一覧を見れたり、色々操作できる
Notaryを動かす
上記までの過程で、node.confの用意とIdentity Managerへの登録のどちらも完了しているので起動可能
java -jar corda.jar でNotary Nodeを起動
network-map.confに記述した設定でssh接続できる
例 ) ssh testuser@localhost -p 2222
Etaro.icon > hashLookup ハッシュ値でそのハッシュ値がNotaryに登録されてるかを見れたり、色々操作できる
例) hashLookup E470FD8A6350A74217B0A99EA5FB71F091C84C64AD0DE0E72ECC10421D03AAC9
NetworkにNodeを追加する
corda.jarを用意
Notaryと同じようにnode.conf (Network map service & Identity Managerのendpointsを追記) と 正当なネットワーク参加者であることを示すnetwork-root-truststore.jks を用意
通常Nodeのnode.confの例
code:node.conf
myLegalName="O=PartyA,L=London,C=GB"
networkServices {
}
devMode = false
cordappSignerKeyFingerprintBlacklist = []
sshd {
port = 2223
}
p2pAddress="localhost:10003"
rpcSettings {
address="localhost:10004"
adminAddress="localhost:10005"
}
security {
authService {
dataSource {
type=INMEMORY
users=[
{
password=test
permissions=[
ALL
]
user=user1
}
]
}
}
}
注意
cordappSignerKeyFingerprintBlacklist = [] の設定はテスト用なので、本番では使わない
各NodeでCordappを動かす の項目も参照
java -jar corda.jar --initial-registration --network-root-truststore-password trustpass --network-root-truststore network-root-truststore.jksでnode.confに記述したIdentity ManagerにNodeを登録
この時、既存のadditional-node-infos、certificates、network-parametersディレクトリ内にファイルがある場合は削除する必要がある
すると、IdentityManagerにNodeがregisterされる
certificates directoryに ( corda-identity-manager-keys.jksで) nodekeystore.jks sslkeystore.jks truststore.jks が生成され、Nodeに付与される
java -jar corda.jarで起動
起動したNodeにはsshで接続
port, usernameやpasswordは node.confに書いてある通り
code:PartyA/node.conf
.....
sshd {
port = 2223
}
.....
security {
authService {
dataSource {
type=INMEMORY
users=[
{
password=test
permissions=[
ALL
]
user=user1
}
]
}
}
}
例 ) ssh user1@localhost -p 2223
各NodeでCordappを動かす
cordappsディレクトリの中に 使用したいCordapp の cordapp.jarファイルを置く
Notaryは、validating notaryの場合はCordappを置くが、non-validating notaryの場合はCordappは置かない
Cordapp への署名
dev modeでは、defaultでdev用のkeystoreで署名される
dev用のkeystoreで署名されたCordappはdevMode=falseだと実行できない(flowが読み込まれない)
テスト目的で動かしたい場合は cordappSignerKeyFingerprintBlacklist = [] を設定する
production mode (devMode = false) の場合は、別のkeystoreでCordappに別途署名する必要がある
Cordappへの署名をしなくても cordappSignerKeyFingerprintBlacklist=[]とnode.confに記述すれば Cordappが動くようになる
cordappSignerKeyFingerprintBlacklistについては以下に記述
ただし、これは本番環境ではNG、ちゃんと署名しよう
Cordapp への署名の条件
あるState AをInputにState TransitionをするTXは、そのState AがIssueされたTXをvalidationしたcontract (cordapp.jar)と同じ署名を持つcordapp.jarを使っていないと、Signature Constraintsでエラーになる
jarsignerによる署名は、同じcordapp.jarに同じkeyで署名したとしても毎回変わる
そのため、このSignature Constraintsにより以下のようなことが実現できる
1. 各Nodeが勝手に作ったり、変更したcordapp.jarを使い初めてもこれまでのStateをinputにしてTX実行はできなくなる
2. ネットワークオーナーが新しいversionのcordapp.jarを作成して各Nodeに配った時(cordappのupdate時)、古いcordapp.jarでは新しいcordapp.jarによって作成されたStateを使用できない
nodekeystore.jks (Corda Nodeのkeystore)やその他独自keyなどで、ネットワークオーナーノードがcontract-cordapp.jarに署名する
そのcontract-cordapp.jarを全員に配布、各Nodeが使用する
TXのInputStateが作成されたTXのcontract-cordapp.jarと同じ署名を持つcontract-cordapp.jarでないとFlowがContract constraintsエラーで落ちる
逆にworkflow-cordapp.jar、つまりFlowのコードは署名がないとflow として読み込まれないが、どんな署名でも動く
Cordapp への署名方法
code:cordappへの署名コマンド
jarsigner -keystore 自ノードのcertificates/nodekeystore.jksを指定 署名したいcordapp.jarの指定 keystoreのalias
keystoreファイルのpasswordを求められるがデフォルトでnodekeystore.jksのpasswordは cordacadevpassでOK
alias cordaclientca、password cordacadevpass は、鍵を生成した時に設定した値を入れ込む(ここではdefault値)
参考 :
code:command例
jarsigner -keystore certificates/nodekeystore.jks cordapps/cordapp-example-contracts-0.1.jar cordaclientca
jarsignerの署名は jarsigner -verify -verbose -certs jarファイル名で検証できる
zip -d jarファイル名 'META-INF/*' or zip -d file.jar 'META-INF/*.SF' 'META-INF/*.RSA' で署名を削除できる
上記のコマンドだと余計なファイルを削除してしまっているのか、一度署名削除すると署名し直してもcouter-flow error でFlowの実行が落ちる...
Flowの実行
nodeにSSH接続した先で、flow listコマンドを実行
以下の3つのflow以外が表示されていれば、Cordappが有効になっている
code:result
net.corda.core.flows.ContractUpgradeFlow$Authorise
net.corda.core.flows.ContractUpgradeFlow$Deauthorise
net.corda.core.flows.ContractUpgradeFlow$Initiate
表示された独自Flowをflow startで実行してみよう!
例) flow start ExampleFlow$Initiator iouValue: 30, otherParty: "O=PartyA,L=London,C=GB"
flow start ExampleFlow$Initiator iouValue: 50, otherParty: "O=PartyB,L=New York,C=US"
flow start ExampleFlow$Initiator iouValue: 80, otherParty: "O=PartyC,L=Paris,C=FR"
flowで作成されたvaultの中のstateを見てみよう
Classを作成する時には、full class pathを指定する
例) run vaultQuery contractStateType: com.example.state.IOUState
NodeのDBに接続してDBの中身も見れる
cordapp-exampleなどにあるSpring Boot サーバを動かしたりすれば、RPCでもFlowを実行できる
他にもたくさんのcommandがあるよ! runを実行して見てみよう
ShellからではなくCorda RPC経由でCordappを呼び出す
以下の流れでCorDappを実行する
{ HTTPクライアント, WEBブラウザ等 } --> { REST API } --> { CorDapp }
手順
あらかじめ全ノードを起動しておく
java -jar corda.jar x 3
以下のようにGradleタスクを実行するとREST APIサーバーが起動する
./gradlew runPartyAServer
./gradlew runPartyBServer
./gradlew runPartyCServer
接続ノードのポートは正しく設定すること
curlでの実行例
PartyAで自分のノード情報を取得
curl -X GET http://localhost:50005/api/example/me
PartyAでiou情報を取得
curl -X GET http://localhost:50005/api/example/ious
ParytBからPartyAへのIOU作成
curl -X POST 'http://localhost:50006/api/example/create-iou?iouValue=10&partyName=O=PartyA,L=London,C=GB' -H 'Content-Type: application/x-www-form-urlencoded'
Signing Serviceを使ってCENMを動かす
Network Map ServiceやIdentity Manager ServiceはデフォルトではLocalSignerというプログラムを実行することで署名しているが、HSM等の外部キーストアを利用したい場合にはスタンドアロンに動くSigning Serviceを使う必要がある。
最初にダウンロードしたCENM zipに含まれているsigner-x.x.x ディレクトリ (signer.jar やbcprov-jdk15on-1.60.jar, bcpkix-jdk15on-1.60.jar と同じディレクトリ)に以下の例のようにsigner.confを作成
以下のコマンドで signer を起動
java -jar signer.jar --config-file signer.conf
設定ファイルの設定例 (LocalにKeystoreを置く例. 本番ではHSMやAzure Key Vaultの利用を推奨)
code:singer.conf
shell = {
sshdPort = 20003
user = "testuser"
password = "password"
}
#############################################
# All individual keys used in signing tasks #
#############################################
# 現在はlocalに置いたkeystoreの指定をしている
# HSMやAzure Key Vaultを使用する場合は、設定が変わる
signingKeys = {
"IdentityManagerLocal" = {
type = LOCAL
password = "password"
keyStore {
file = corda-identity-manager-keys.jks
password = "password"
}
alias = "cordaidentitymanagerca"
},
"NetworkMapLocal" = {
type = LOCAL
password = "password"
keyStore {
file = corda-network-map-keys.jks
password = "password"
}
alias = "cordanetworkmap"
}
}
##########################################################
# All ENM service endpoints for fetching/persisting data #
##########################################################
# networkmap, identity-manager(issuance workflow, revocation workflow)のendpointを指定している
serviceLocations = {
"network-map" = {
host = localhost
port = 5050
verbose = true
},
"identity-manager" = {
host = localhost
port = 5051
verbose = true
},
"revocation" = {
host = localhost
port = 5052
verbose = true
}
}
###################################################
# Signing tasks to be run (manually or scheduled) #
###################################################
# Signerが行う処理の設定を書く
# ここで指定したnameがsignerのshell内で使用できる
signers = {
"Example CSR Signer" = {
type = CSR
signingKeyAlias = "IdentityManagerLocal"
serviceLocationAlias = "identity-manager"
validDays = 7300 # 20 year certificate expiry
# scheduleを設定するとこのタスクが定期実行される
schedule {
interval = 1s
}
},
"Example CRL Signer" = {
type = CRL
signingKeyAlias = "IdentityManagerLocal"
serviceLocationAlias = "revocation"
updatePeriod = 86400000 # 1 day CRL expiry
schedule {
interval = 60s
}
},
"Example Network Map Signer" = {
type = NETWORK_MAP
signingKeyAlias = "NetworkMapLocal"
serviceLocationAlias = "network-map"
schedule {
interval = 1s
}
},
"Example Network Parameters Signer" = {
type = NETWORK_PARAMETERS
signingKeyAlias = "NetworkMapLocal"
serviceLocationAlias = "network-map"
schedule {
interval = 10s
}
}
}
signing serviceを起動したら、順次identity manager, network map serviceを起動する。このとき、それぞれの設定ファイルは以下のように設定する。
code:identity-manager.conf
address = "localhost:10000"
database {
driverClassName = org.h2.Driver
url = "jdbc:h2:file:./identity-manager-persistence;DB_CLOSE_ON_EXIT=FALSE;LOCK_TIMEOUT=10000;WRITE_DELAY=0;AUTO_SERVER_PORT=0"
user = "example-db-user"
password = "example-db-password"
}
shell {
sshdPort = 10002
user = "testuser"
password = "password"
}
workflows {
"issuance" = {
type = ISSUANCE
updateInterval = 1000
# このenmListenerに指定したportにSigning Serviceがrequestしてくる
enmListener {
port = 5051
reconnect = true
}
plugin {
pluginClass = "com.r3.enmplugins.approveall.ApproveAll"
}
},
"revocation" = {
type = REVOCATION
# このenmListenerに指定したportにSigning Serviceがrequestしてくる
enmListener {
port = 5052
reconnect = true
}
plugin {
pluginClass = "com.r3.enmplugins.approveall.ApproveAll"
}
crlCacheTimeout = 2000
# pki-toolsで生成したcrl filesを指定する
}
}
code:network-map.conf
address = "localhost:20000"
database {
driverClassName = org.h2.Driver
url = "jdbc:h2:file:./network-map-persistence;DB_CLOSE_ON_EXIT=FALSE;LOCK_TIMEOUT=10000;WRITE_DELAY=0;AUTO_SERVER_PORT=0"
user = "example-db-user"
password = "example-db-password"
}
shell {
sshdPort = 20002
user = "testuser"
password = "password"
}
# このenmListenerに指定したportにSigning Serviceがrequestしてくる
enmListener {
port = 5050
reconnect = true
}
pollingInterval = 1000
checkRevocation = false
このidentity-manager.confはCRLやrevocation workflowの設定もしてある。
Signing Service 設定例
CRR(Certificate Revocation Request)の実行
crr-submission-tool-<VERSION>.jar と Identity ManagerのCRR受付endpointを指定して以下のコマンドで実行する
java -jar crr-submission-tool-<VERSION>.jar --submission-url http://<<CORDA_DOMAIN>>/certificate-revocation-request
例
java -jar crrsubmissiontool.jar --submission-url http://localhost:5052
このRequestがIdentity Managerに届き、以下のWorkFlowが実行される
Workflowについて
Identity Managerには起点となる2つのWorkflowがある
また、それぞれのWorkflowの承認フローは2種類ある
自動承認
JIRAワークフローに接続
どちらの承認フローを利用するか必ず選ばなければならない。
CRL を更新するには corda-tls-crl-signer-keys.jks を持っている必要がある
node.conf の各種設定
node.confでNotary, 各Nodeの設定を書く
myLegalName
code:node.conf
myLegalName="O=NotaryA,L=London,C=GB"
Nodeの legal identity
Nodeの公開鍵をhuman-readableに扱うalias
Network MapにもこのLegal identityが登録される
ここに設定したLegalNameが、Identity Managerへ登録する際に付与されるcertificates dirの中の証明書と一致するかどうかが起動時にcheckされる
devmode
code:node.conf
devMode = false
trueだとbootstrapperを使用して構築
CENMを使う場合は、false
networkServices
code:node.conf
networkServices {
}
doorman = identity manager の向き先とnetwork map の向き先を指定する
devmode = falseの時だけ指定が必要
devmode = trueの時はそもそも、identity managerもnetwork map serviceも存在しない
p2pAddress
code:node.conf
p2pAddress="localhost:10003"
他のNodeとやり取りする際の口を設定
rpcSetting
code:node.conf
rpcSettings {
address="localhost:10004"
adminAddress="localhost:10005"
}
APIやクライアントから叩く口を設定
rpcUsers
code:node.conf
rpcUsers=[
{
user=testuser
password=password
permissions=[
ALL
]
}
]
NodeのRPC口からアクセスできるuserのlistを定義する
userはusername
passwordはパスワード
permissionsは、「そのuserがどのFlowを実行できるか」の設定
例
ALLとすると、全てのFlowをRPC経由で実行可能
StartFlow.foo.bar.*などとすると、foo.bar packageの全てのFlowを実行可能
sshd
code:node.conf
sshd {
port = 2222
}
この設定を書いておくと、sshでnodeのマネジメントshellに入れるようになる
認証は RPCと同じになる(?)
security
code:node.conf
security {
authService {
dataSource {
type=INMEMORY
users=[
{
password=test
permissions=[
ALL
]
user=user1
}
]
}
}
}
RPCアクセスの認証認可情報を記述できる
rpcUsersとsecurityは同時に記述できない
securityを利用することでより高度なユーザー管理ができるようになる
notary
code:node.conf
notary {
validating=false
}
Notary Nodeの node.confにだけ記述する設定
validating true or falseでvalidating notaryかnon-validating notaryかを指定
他にも raft bftSMaRt などのNotary Clusterに関する設定をすることもできるが experimentalな機能となっている
参考